package edu.tec.mty.core;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import edu.tec.mty.core.connection.*;
import edu.tec.mty.core.modules.Self;
import edu.tec.mty.core.modules.SelfModel;
import edu.tec.mty.core.modules.Server;
import edu.tec.mty.core.modules.models.Position;

public class Commands {
	
	private Dispatcher dispatcher;
	private Pattern widthPattern = Pattern.compile("(narrow|normal|wide)");
	public Pattern sayLanguage = Pattern.compile("[\\-0-9a-zA-Z \\(\\)\\.\\+\\*/\\?\\<\\>_]*");
	private SelfModel playerModel;
	private Self player;
	
	public Commands() {
		
	}
	
	public Commands(Dispatcher dispatcher, Information information) {
		this.dispatcher = dispatcher;
		this.player = information.getReferenceToPlayer();
		this.playerModel = this.player.getReferenceToPlayerModel();
	}
	
	//player
	public void catchBall(int direction) {
		String command = "(catch " + Integer.toString(direction) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
	}
	
	//player
	//deprecated
	public void dash(int power) {
		String command = "(dash " + Integer.toString(power) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
	}
	
	//player
	public boolean dash(double power, double direction) {
		if ((power >= Server.MINPOWER && power <= Server.MAXPOWER) && (direction >= Server.MINMOMENT && direction <= Server.MAXMOMENT)) {
			String command = "(dash " + Double.toString(power) + " " + Double.toString(direction) + ")";
			this.dispatcher.putCommandInQueue(command, 1);
			switch (Self.STATUS) {
			case Self.IDLE:
				this.player.changeStatus(Self.WILL_TO_DASH);
				break;
			case Self.WILL_TO_STOP:
				this.player.changeStatus(Self.DASHING);
				break;
			case Self.WILL_TO_DASH:
				this.player.changeStatus(Self.DASHING);
				break;
			case Self.WILL_TO_TURN:
				this.player.changeStatus(Self.DASHING);
				break;
			case Self.TURNING:
				this.player.changeStatus(Self.DASHING);
				break;
			case Self.DASHING:
				break;
			}
			return true;
		} else {
			return false;
		}
	}
	
	//player
	public void kick(double power, double direction) {
		String command = "(kick " + Double.toString(power) + " " + Double.toString(direction) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
	}
	
	//player
	public void tackle(double power, boolean willingToFoul) {
		String command = "(tackle " + Double.toString(power);
		command += willingToFoul ? " true)" : " false)";
		this.dispatcher.putCommandInQueue(command, 1);
	}
	
	//player
	public void move(double x, double y) {
		String command = "(move " + Double.toString(x) + " " + Double.toString(y) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
		this.playerModel.updateXY(x, y);
	}
	
	//player
	public void turn(double moment) {
		String command = "(turn " + Double.toString(moment) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
		switch (Self.STATUS) {
		case Self.IDLE:
			this.player.changeStatus(Self.WILL_TO_TURN);
			break;
		case Self.WILL_TO_STOP:
			this.player.changeStatus(Self.TURNING);
			break;
		case Self.WILL_TO_DASH:
			this.player.changeStatus(Self.TURNING);
			break;
		case Self.DASHING:
			this.player.changeStatus(Self.TURNING);
			break;
		case Self.WILL_TO_TURN:
			this.player.changeStatus(Self.TURNING);
			break;
		case Self.TURNING:
			break;
		}
	}
	
	//player
	public boolean say(String message) {
		if (message.length() <= Server.SAY_MSG_SIZE && this.sayLanguage.matcher(message).matches()) {
			String command = "(say \"" + message + "\")";
			this.dispatcher.putCommandInQueue(command, 0);
			return true;
		} else {
			return false;
		}
	}
	
	public void earEnable(boolean on, boolean myTeam, boolean partial) {
		String command = "(ear ";
		command += on ? "on " : "off ";
		command += myTeam ? "our " : "opp ";
		command += partial ? "partial)" : "complete)";
		this.dispatcher.putCommandInQueue(command, 0);
	}
	
	//player
	public boolean turnNeck(double angle) {
		if (angle >= Server.MINMOMENT && angle <= Server.MAXMOMENT) {
			String command = "(turn_neck " + Double.toString(angle) + ")";
			this.dispatcher.putCommandInQueue(command, 0);
			return true;
		} else {
			return false;
		}
	}
	
	//player
	public void pointTo(Position position) {
		Position playerPosition = this.playerModel.getPosition();
		String command = "(pointto " + Double.toString(playerPosition.getDistanceTo(position)) + " " + Double.toString(playerPosition.getAngleFromBodyTo(position)) + ")";
		this.dispatcher.putCommandInQueue(command, 0);
	}
	
	//player
	public void setSynchronousViewMode() {
		this.dispatcher.putCommandInQueue("(synch_see)", 0);
	}
	
	//player
	public boolean changeView(String width) {
		Matcher widthMatcher = widthPattern.matcher(width);
		if (widthMatcher.matches()) {
			String command = "(change_view " + width + ")";
			this.dispatcher.putCommandInQueue(command, 0);
			return true;
		} else {
			return false;
		}
	}
	
	//player
	//deprecated
	public void changeView(String width, String quality) {		
		Matcher widthMatcher = widthPattern.matcher(width);
		Pattern qualityPattern = Pattern.compile("(high|low)");
		Matcher qualityMatcher = qualityPattern.matcher(quality);
		if (widthMatcher.matches() && qualityMatcher.matches()) {
			String command = "(change_view " + width + " " + quality + ")";
			this.dispatcher.putCommandInQueue(command, 0);
		}
	}
	
	//player
	public void score() {
		this.dispatcher.putCommandInQueue("(score)", 0);
	}
	
	//player
	public void senseBody() {
		this.dispatcher.putCommandInQueue("(sense_body)", 0);
	}
	
	//trainer
	public void changeMode(String playMode) {
		Pattern playModePattern = Pattern.compile("");
		Matcher playModeMatcher = playModePattern.matcher(playMode);
		if (playModeMatcher.matches()) {
			String command = "(change_mode" + playMode + ")";
			this.dispatcher.putCommandInQueue(command, 0);
		}
	}
	
	//trainer, coach
	public void changePlayerType(int player, int type) {
		String command = "(change_player_type " + Integer.toString(player) + " " + Integer.toString(type) + ")";
		this.dispatcher.putCommandInQueue(command, 1);
	}
	
	//trainer, coach
	public void setEyeMode(boolean state) {
		String command = "(eye ";
		command += state ? " on)" : " off)";
		this.dispatcher.putCommandInQueue(command, 0);
	}
	
	public void clearCommands() {
		this.dispatcher.clearCommands();
	}

	//Test
	
	public static void main(String[] args) {
		Commands c = new Commands();
		if (c.sayLanguage.matcher("hola?_ >").matches()) {
			System.out.println("it works!");
		} else {
			System.out.println("it doesnt work");
		}
	}
	
}
